
void text_set_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
void spawn_vehicle(int vID);
void scroller_vertical(bool up, bool down, int *value, int min, int max);
void GivePlayerWeapon(int weaponID, int ammo);

// 2. Bezpieczna funkcja pobierająca nazwę z Twojej tablicy
const char* GetMyVehicleName(int id) {
    int index = id; // Przesunięcie, bo auta zaczynają się od 400
    if (index >= 0 && index < 212) {
        return vehicleNames[index];
    }
    return "UNKNOWN";
}

int MyGetWeaponModel(int weaponID) {
    // Tablica indeksowana przez ID broni (0-46)
    static int weaponModelIDs[] = {
        -1, 331, 333, 334, 335, 336, 337, 338, 339, 341, // 0-9
        321, 322, 323, 324, 325, 326, 342, 343, 344, -1, // 10-19
        -1, -1, 346, 347, 348, 349, 350, 351, 352, 353, // 20-29
        355, 356, 372, 357, 358, 359, 360, 361, 362, 363, // 30-39
        364, 365, 366, 367, 368, 369, 371                // 40-46
    };

    if (weaponID >= 0 && weaponID <= 46) return weaponModelIDs[weaponID];
    return -1;
}

void* GetPlayerPed() {
    return *(void**)0xB7CD98; 
}

void DrawMegaHealthBar(float x, float y, float maxFullWidth) {
    void* pPlayer = *(void**)0xB7CD98;
    if (!pPlayer) return;

    // Pobieramy aktualne życie (0.0 - 100.0 lub 200.0)
    float health = *(float*)((DWORD)pPlayer + 0x540);
    float maxHealth = 100.0f; // Możesz to pobrać z 0x544, jeśli masz ulepszenia

    // Obliczamy procentową szerokość paska
    float ratio = health / maxHealth;
    if (ratio > 1.0f) ratio = 1.0f;
    if (ratio < 0.0f) ratio = 0.0f;

    float currentWidth = maxFullWidth * ratio;

    // 1. TŁO (Ciemnoczerwone)
    CRect bg = { x, y, x + maxFullWidth, y + 20.0f };
    CRGBA bgColor = { 50, 0, 0, 180 };
    DrawRect(bg, bgColor);

    // 2. WYPEŁNIENIE (Jasnoczerwone)
    CRect bar = { x, y, x + currentWidth, y + 20.0f };
    CRGBA barColor = { 255, 0, 0, 255 };
    DrawRect(bar, barColor);
    
    // 3. NAPIS (Opcjonalnie)
    //char buf[32];
    //sprintf(buf, "HP: %.0f", health);
    //text_set_color(255,255,255,255);
    //FontPrintString(x + 5.0f, y + 2.0f, buf);
}
/*
void ToggleCheat(int index) {
    // A. FLAGI (Zapisywanie wartości pod adres, np. Amunicja)
    if (menu[index].type == 1) {
        menu[index].value = !menu[index].value;
        *(unsigned char*)0x96916D = (unsigned char)menu[index].value;
    }

    // B. CALL Z PARAMETREM (np. 0x4385B0 - GiveWeapon(player, id))
    else if (menu[index].action == true) {
        // Definicja funkcji przyjmującej parametr int (np. ID broni)
        // __cdecl lub __stdcall zależnie od wersji gry (zazwyczaj cdecl dla GTA)
        typedef void (__cdecl *GameFuncWithParam)(int); 
        GameFuncWithParam CallGameAction = (GameFuncWithParam)0x4385B0;
        
        // Wywołujemy funkcję, przekazując parametr zapisany w menu
        CallGameAction(menu[index].param); 
    }
}

void ToggleCheat(int index) {
    // A. FLAGI (Zapisywanie wartości pod adres, np. Amunicja)
    if (menu[index].type == 1) {
        menu[index].value = !menu[index].value;
        *(unsigned char*)0x96916D = (unsigned char)menu[index].value;
    }

    // B. CALL Z PARAMETREM (np. 0x4385B0 - GiveWeapon(player, id))
    else if (menu[index].action == true) {
        // Definicja funkcji przyjmującej parametr int (np. ID broni)
        // __cdecl lub __stdcall zależnie od wersji gry (zazwyczaj cdecl dla GTA)
        typedef void (__cdecl *GameFuncWithParam)(int); 
        GameFuncWithParam CallGameAction = (GameFuncWithParam)0x4385B0;
        
        // Wywołujemy funkcję, przekazując parametr zapisany w menu
        CallGameAction(menu[index].param); 
    }
}
*/

void SetExplosiveAmmo(int weaponID, bool enable) {
    uintptr_t weaponStatsBase = 0xC8AAB8;
    uintptr_t weaponAddress = weaponStatsBase + (weaponID * 0x70); 

    // Offset 0x1C - Weapon Type / Projectile Type
    int* pProjectileType = (int*)(weaponAddress + 0x1C);

    if (enable) {
        // Zmieniamy na 4 (kod dla amunicji wybuchowej/rakietowej w silniku)
        *pProjectileType = 4; 
    } else {
        // Powrót do 1 (zwykła kula)
        *pProjectileType = 1; 
    }
}


void SetDualWield(int weaponID, bool enable) {
    uintptr_t weaponStatsBase = 0xC8AAB8;
    // Struktura CWeaponInfo dla poziomu "Hitman" (to ten poziom daje dual wield)
    // Każda broń ma 3 poziomy skilla, przesunięcie między nimi to zwykle 0x28 lub 0x70
    uintptr_t weaponAddress = weaponStatsBase + (weaponID * 0x70); 

    // Offset flag to zazwyczaj 0x24 w strukturze broni
    unsigned int* pFlags = (unsigned int*)(weaponAddress + 0x24);

    if (enable) {
        // Dodajemy flagę 0x1 (wykorzystujemy sumę bitową)
        *pFlags |= 0x000001; 
        
        // Dodatkowo ustawiamy statystyki skilla na 1000 (Hitman)
        // Adres skilli gracza zaczyna się od 0xB79380
        // AK-47 to skill nr 10
        *(float*)(0xB79380 + (10 * 4)) = 1000.0f;
    } else {
        // Usuwamy flagę
        *pFlags &= ~0x000001;
    }
}

void SetInfiniteAmmo(bool enable) {
    // Adresy odpowiedzialne za amunicję (v1.0)
    uintptr_t addrAmmo = 0x969168; // Globalna flaga amunicji
    uintptr_t addrNoReload = 0x969169; // Flaga braku przeładowania

    if (enable) {
        *(unsigned char*)addrAmmo = 1;      // Włącz nieskończoną amunicję
        *(unsigned char*)addrNoReload = 1;  // Włącz brak przeładowania (strzelasz non-stop)
        
        // Dodatkowo: Lockowanie nabojów w aktualnym magazynku (offset 0x5BC w strukturze gracza)
        void* pPlayer = GetPlayerPed();
        if (pPlayer) {
            // Ustawiamy dużą ilość amunicji dla aktualnej broni
            int currentSlot = *(int*)((uintptr_t)pPlayer + 0x718); // Aktualny slot broni
            // (Można tu dopisać pętlę ustawiającą amunicję na 9999)
        }
    } else {
        *(unsigned char*)addrAmmo = 0;
        *(unsigned char*)addrNoReload = 0;
    }
}


void UpdateWeaponStats() {
    void* pPlayer = GetPlayerPed();
    if (!pPlayer) return;

    // Pobierz ID aktualnej broni (offset 0x740)
    int weaponID = *(int*)((uintptr_t)pPlayer + 0x740);
    if (weaponID <= 0) return;

    uintptr_t weaponStatsBase = 0xC8AAB8;
    uintptr_t weaponAddress = weaponStatsBase + (weaponID * 0x70); 

    // 1. SUPER RANGE
    float* pRange = (float*)(weaponAddress + 0x04);
    if (super_range) *pRange = 1000.0f;
    else *pRange = 60.0f; // Wartość domyślna

    // 2. SUPER DAMAGE
    float* pDamage = (float*)(weaponAddress + 0x22);
    if (super_damage) *pDamage = 9999.0f;
    else *pDamage = 25.0f;

    // 3. SUPER ACCURACY
    float* pAccuracy = (float*)(weaponAddress + 0x08);
    if (super_Accuracy) *pAccuracy = 10.0f;
    else *pAccuracy = 0.5f;

    // 4. SUPER SHOT SPEED (Rapid Fire)
    float* pAnimSpeed = (float*)(weaponAddress + 0x14);
    if (super_speed) *pAnimSpeed = 0.1f;
    else *pAnimSpeed = 1.0f;
    
    if (dual_ak47){SetDualWield(weaponID,true);}
    if (explosive_ammo){ SetExplosiveAmmo(weaponID, true); }
}

void SetMaxHealth(bool enable) {
    void* pPlayer = GetPlayerPed();
    if (!pPlayer) return;

    // Offsety dla CJ (v1.0):
    // 0x540 - Aktualne Zdrowie (float)
    // 0x544 - Maksymalne Zdrowie (float)

    float* pCurrentHealth = (float*)((uintptr_t)pPlayer + 0x540);
    float* pMaxHealth = (float*)((uintptr_t)pPlayer + 0x544);

    if (enable) {
        *pMaxHealth = 200.0f;     // Ustawia limit na maksimum (półkole)
        *pCurrentHealth = 200.0f; // Od razu leczy CJ-a do tego poziomu
    } else {
        // Powrót do standardowego limitu (jeśli chcesz)
        *pMaxHealth = 100.0f;
    }
}

void SetWantedLevel(int level) {
    
    if (level < 0) level = 0;
    if (level > 6) level = 6;

    // Tablica progów punktowych dla gwiazdek (v1.0)
    int wantedPoints[] = { 0, 50, 180, 550, 1200, 3200, 7000 };

    // 1. Ustawiamy punkty (to wymusza reakcję AI policji)
    *(int*)0x58DB64 = wantedPoints[level]; 
    
    // 2. Ustawiamy wizualny poziom gwiazdek
    *(int*)0x58DB60 = level;


}

int GetWantedLevel() {
    int level = *(int*)0x58DB60;
    return level;
}

bool never_wanted_active = false; // Toggle w menu

void ProcessNeverWanted() {
    if (never_wanted_active) {
        *(int*)0x58DB60 = 0; // Gwiazdki na 0
        *(int*)0x58DB64 = 0; // Punkty na 0
        
        // Dodatkowy adres blokujący przyrost punktów (v1.0)
        *(unsigned char*)0x969171 = 1; 
    } else {
        *(unsigned char*)0x969171 = 0;
    }
}


void SetPoliceWeapons(int newWeaponID) {
    // Przeszukujemy pulę pedów (v1.0 ma pulę pod adresem 0xB74490)
    uintptr_t pedPoolBase = *(uintptr_t*)0xB74490;
    int maxPeds = *(int*)(pedPoolBase + 0x8); // Rozmiar puli

    for (int i = 0; i < maxPeds; i++) {
        uintptr_t pPed = *(uintptr_t*)(pedPoolBase + (i * 0x4));
        if (!pPed) continue;

        // Sprawdzamy, czy to policjant (PedType 2 w GTA SA)
        // Offset PedType to zazwyczaj 0x590 w strukturze CPed
        int pedType = *(int*)(pPed + 0x590);
        
        if (pedType == 2) { // 2 = COP
            // Dajemy broń (używając wewnętrznej funkcji lub offsetów slotów)
            // Najprościej: nadpisujemy slot aktualnej broni
            int* pCurrentWeapon = (int*)(pPed + 0x718); 
            *pCurrentWeapon = newWeaponID;
            
            // Opcjonalnie: ustawiamy amunicję, żeby nie przestali strzelać
            *(int*)(pPed + 0x5A0) = 9999; 
        }
    }
}


void ProcessPoliceWeapons(int newWeaponID, bool enable) {
    if (!enable) return;

    // Pobierz pulę pedów (v1.0)
    uintptr_t poolAddr = *(uintptr_t*)0xB74490;
    if (!poolAddr) return;

    int maxPeds = *(int*)(poolAddr + 0x8);
    uintptr_t pedsArray = *(uintptr_t*)poolAddr;

    for (int i = 0; i < maxPeds; i++) {
        uintptr_t pPed = *(uintptr_t*)(pedsArray + (i * 0x1)); // Dostęp do struktury CPed
        if (!pPed) continue;

        // 1. Sprawdź czy to policjant (PedType == 2)
        int pedType = *(int*)(pPed + 0x590);
        if (pedType == 2) {
            
            // 2. Sprawdź aktualną broń (Slot aktualny: 0x718)
            int currentWeapon = *(int*)(pPed + 0x718);
            
            // Jeśli policjant ma inną broń niż nasza docelowa, podmień ją
            if (currentWeapon != newWeaponID) {
                // Ustawiamy model broni
                *(int*)(pPed + 0x718) = newWeaponID;
                
                // Ustawiamy amunicję (Offset 0x5A0 dla aktualnego slotu)
                *(int*)(pPed + 0x5A0) = 999;
                
                // Wymuszamy, aby AI wiedziało, że ma nową broń
                // (Czasami trzeba zresetować stan AI, ale zazwyczaj samo nadpisanie wystarcza)
            }
        }
    }
}

void SetFriendlyPolice(bool enable) {
    uintptr_t poolAddr = *(uintptr_t*)0xB74490;
    if (!poolAddr) return;

    int maxPeds = *(int*)(poolAddr + 0x8);
    // Przesunięcia w puli zależą od wersji, zazwyczaj to tablica wskaźników
    uintptr_t pedsArray = *(uintptr_t*)poolAddr; 

    for (int i = 0; i < maxPeds; i++) {
        uintptr_t pPed = *(uintptr_t*)(pedsArray + (i * 0x4)); // 0x4 dla v1.0
        if (!pPed) continue;

        // Sprawdź czy to COP (PedType 2)
        int* pPedType = (int*)(pPed + 0x590);
        
        if (enable) {
            if (*pPedType == 2) { // Jeśli to policjant
                // Zmień typ na PLAYER_GANG (Type 24) lub PLAYER_GROUP
                // Dzięki temu policja uzna Cię za swojego lidera/sojusznika
                *pPedType = 24; 
                
                // Ustaw relację na "Respect" (0 = Respect, 4 = Hate)
                // Offset relacji względem gracza to ok. 0x4AC (zależnie od struktury)
                *(int*)(pPed + 0x4AC) = 0; 
            }
        } else {
            // Przywróć typ COP (2)
            if (*pPedType == 24) *pPedType = 2;
        }
    }
}

void MakePoliceBodyguards(bool enable) {
    if (!enable) return;

    uintptr_t pPlayer = (uintptr_t)GetPlayerPed();
    if (!pPlayer) return;

    // Pobierz wskaźnik do grupy gracza (v1.0 offset 0x79C w CPed gracza)
    uintptr_t pPlayerGroup = *(uintptr_t*)(pPlayer + 0x79C);
    if (!pPlayerGroup) return;

    uintptr_t poolAddr = *(uintptr_t*)0xB74490;
    int maxPeds = *(int*)(poolAddr + 0x8);
    uintptr_t pedsArray = *(uintptr_t*)poolAddr;

    for (int i = 0; i < maxPeds; i++) {
        uintptr_t pPed = *(uintptr_t*)(pedsArray + (i * 0x4));
        if (!pPed || pPed == pPlayer) continue;

        // Sprawdź czy to policjant (PedType 2)
        int pedType = *(int*)(pPed + 0x590);
        if (pedType == 2) {
            // 1. Zmień typ na PLAYER_GROUP (żeby silnik pozwolił na rekrutację)
            *(int*)(pPed + 0x590) = 24; 

            // 2. Dodaj do grupy gracza (Funkcja gry: 0x5F7A40 - CPlayerGroup::AddFollower)
            // Jeśli nie chcesz wywoływać funkcji, nadpisujemy wskaźnik grupy (offset 0x79C)
            *(uintptr_t*)(pPed + 0x79C) = pPlayerGroup;

            // 3. Ustaw "Intelligence" na pomocnika (Leader to Player)
            // Offset 0x5A4 to zazwyczaj Decision Maker
            *(int*)(pPed + 0x5A4) = *(int*)(pPlayer + 0x5A4);
        }
    }
}

0 – Ballas
1 – Grove Street Families
2 – Los Santos Vagos
3 – San Fierro Rifa
4 – Da Nang Boys
5 – Mafia (Italian)
6 – Triads
7 – Varrios Los Aztecas

void SetGangWeapons(int gangID, int w1, int w2, int w3) {
    // Adres bazowy broni gangów (v1.0)
    // Każdy gang ma 3 sloty po 4 bajty (razem 12 bajtów na gang)
    uintptr_t gangBase = 0x5D3A90 + (gangID * 12);

    *(int*)(gangBase + 0) = w1; // Broń 1
    *(int*)(gangBase + 4) = w2; // Broń 2
    *(int*)(gangBase + 8) = w3; // Broń 3
}

void SetGangsEverywhere(bool enable) {
    // 1. Główne flagi silnika (v1.0)
    *(unsigned char*)0x969150 = enable ? 1 : 0; 
    *(unsigned char*)0x969176 = enable ? 1 : 0;

    // 2. Opcjonalnie: Zmiana mnożnika spawnu (żeby było ich więcej)
    // Adres 0x8D244C kontroluje gęstość grup (standardowo 1.0f)
    *(float*)0x8D244C = enable ? 2.5f : 1.0f;

    if (enable) {
        PrintStringA("~G~GANGS EVERYWHERE ACTIVATED", 1000, 1, false);
    }
}

unsigned char gangModelsBackup[42 * 8]; // 8 gangów po 42 bajty każdy

void BackupOriginalGangModels() {
    // Kopiujemy całą sekcję 336 bajtów z pamięci gry do naszej tablicy
    memcpy(gangModelsBackup, (void*)0xC0FA3C, 42 * 8);
}

void ResetGangModels() {
    // Przywracamy dane z backupu do pamięci gry
    memcpy((void*)0xC0FA3C, gangModelsBackup, 42 * 8);
    PrintStringA("~G~GANG MODELS RESET TO DEFAULT", 1000, 1, false);
}



void SetGangModel(int gangID, int slot, int newModelID) {
    // 1. Baza tablicy modeli gangów
    uintptr_t gangModelsBase = 0xC0FA3C;

    // 2. Obliczamy adres konkretnego gangu (każdy gang ma blok 42 bajtów)
    // gangID: 0-Ballas, 1-Grove, itd.
    uintptr_t gangAddress = gangModelsBase + (gangID * 42);

    // 3. Obliczamy adres slotu (każdy slot to 2 bajty, max 21 slotów)
    // slot: 0 to pierwszy model gangu, 1 to drugi, itd.
    uintptr_t slotAddress = gangAddress + (slot * 2);

    // 4. Zapisujemy nowe ID modelu (short = 2 bajty)
    *(unsigned short*)slotAddress = (unsigned short)newModelID;
}


void ResetGangWeapons() {
    if (weaponBackupCreated) {
        // Wklejamy oryginał z powrotem pod adres 0x5D3A90
        memcpy((void*)0x5D3A90, gangWeaponsOriginal, 96);
        PrintStringA("~G~GANG WEAPONS RESET", 1000, 1, false);
    }
}

// 8 gangów * 3 bronie * 4 bajty = 96 bajtów
unsigned char gangWeaponsOriginal[96]; 
bool weaponBackupCreated = false;

void BackupGangWeapons() {
    if (!weaponBackupCreated) {
        // Kopiujemy oryginalne bronie spod adresu 0x5D3A90
        memcpy(gangWeaponsOriginal, (void*)0x5D3A90, 96);
        weaponBackupCreated = true;
    }
}

void SetWaterLevel(float level) {
    // Adres bazowy poziomu wody (v1.0)
    *(float*)0xC228B0 = level;
    
    // Dodatkowo: w niektórych wersjach trzeba zaktualizować 
    // statyczny poziom dla renderera (opcjonalnie)
    *(float*)0x850F80 = level; 
}

void SetAllZonesToGrove() {
    // Adres bazowy stref (v1.0): 0xBA1DF0
    // Liczba stref (v1.0): 0xBA1DE8 (zazwyczaj ok. 100)
    int totalZones = *(int*)0xBA1DE8;
    uintptr_t zonesBase = 0xBA1DF0;

    for (int i = 0; i < totalZones; i++) {
        // Każda struktura strefy ma 28 bajtów (0x1C)
        uintptr_t currentZone = zonesBase + (i * 0x1C);
        
        // Offset 0x18 to ID gangu kontrolującego strefę
        // 0 = Ballas, 1 = Grove Street, 2 = Vagos
        *(unsigned char*)(currentZone + 0x18) = 1; 

        // Opcjonalnie: Ustawienie 100% kontroli dla Grove (gęstość)
        // Offsety 0x11, 0x12, 0x13 to gęstość Ballas, Grove, Vagos
        *(unsigned char*)(currentZone + 0x11) = 0;   // Ballas density 0
        *(unsigned char*)(currentZone + 0x12) = 255; // Grove density max
        *(unsigned char*)(currentZone + 0x13) = 0;   // Vagos density 0
    }
    
    // Wymuszenie odświeżenia radaru (mapy)
    ((void (__cdecl *)())0x5821F0)(); 
}

void ActivateGreenWorld(bool enable) {
    if (enable) {
        // 1. Zrób mapę zieloną
        SetAllZonesToGrove();

        // 2. Włącz spawn gangów wszędzie
        *(unsigned char*)0x969150 = 1; 
        *(unsigned char*)0x969176 = 1;

        // 3. Włącz wojny gangów wszędzie
        *(unsigned char*)0x969174 = 1;

        PrintStringA("~G~GREEN WORLD ACTIVATED", 1000, 1, false);
    } else {
        // Przywrócenie domyślnych flag
        *(unsigned char*)0x969150 = 0;
        *(unsigned char*)0x969174 = 0;
    }
}

void ProcessGreenPolice(bool enable) {
    if (!enable) return;

    // Pobierz pulę pojazdów (v1.0: 0xB74494)
    uintptr_t vehiclePool = *(uintptr_t*)0xB74494;
    int maxVehs = *(int*)(vehiclePool + 0x8);
    uintptr_t vehsArray = *(uintptr_t*)vehiclePool;

    for (int i = 0; i < maxVehs; i++) {
        uintptr_t pVeh = *(uintptr_t*)(vehsArray + (i * 0x4));
        if (!pVeh) continue;

        // Sprawdzamy model (ID 596-599 to radiowozy)
        int modelID = *(int*)(pVeh + 0x221); // Uproszczony offset modelu
        if (modelID >= 596 && modelID <= 599) {
            
            // 1. Zmień kolor na Zielony (Grove Green to zazwyczaj ID 86 lub 114)
            *(unsigned char*)(pVeh + 0x430) = 86; // Primary Color
            *(unsigned char*)(pVeh + 0x431) = 86; // Secondary Color

            // 2. Podmień kierowcę (Driver offset 0x460)
            uintptr_t pDriver = *(uintptr_t*)(pVeh + 0x460);
            if (pDriver) {
                int* pPedType = (int*)(pDriver + 0x590);
                if (*pPedType == 2) { // Jeśli to COP
                    *pPedType = 24;   // Zmień na PLAYER_GANG (Grove)
                    
                    // Opcjonalnie: Zmień model kierowcy na Grove (ID 105-107)
                    // Wymaga wcześniej RequestAndLoadModel(105);
                    *(unsigned short*)(pDriver + 0x22) = 105; 
                }
            }
        }
    }
}

bool green_world_active = false;

// W pętli głównej (co klatkę):
void MainLoop() {
    if (green_world_active) {
        SetAllZonesToGrove();     // Mapa na zielono
        ProcessGreenPolice(true);  // Radiowozy na zielono + Grove Drivers
        
        // Zablokuj gwiazdki, żeby "zielona policja" Cię nie goniła
        *(int*)0x58DB60 = 0; 
    }
}


void SetGreenAtmosphere(bool enable) {
    // 1. ZIELONA WODA
    // Adresy kolorów wody (RGBA): 0x3D4D5C (standardowe uśrednione wartości)
    // W SA (v1.0) kolory wody są w tablicy struktur 0x869A40
    if (enable) {
        *(unsigned char*)0x869A40 = 0;   // Red
        *(unsigned char*)0x869A41 = 255; // Green (MAX)
        *(unsigned char*)0x869A42 = 0;   // Blue
        *(unsigned char*)0x869A43 = 150; // Alpha (przezroczystość)
    }

    // 2. ZIELONE NIEBO (Timecycle Hack)
    // Nadpisujemy aktualnie renderowany kolor nieba (Sky Top)
    // Adresy dynamiczne w pamięci (v1.0):
    float* skyTopR = (float*)0xB7C4A4;
    float* skyTopG = (float*)0xB7C4A8;
    float* skyTopB = (float*)0xB7C4AC;

    if (enable) {
        *skyTopR = 0.0f;
        *skyTopG = 1.0f; // Intensywna zieleń
        *skyTopB = 0.0f;
        
        // Dodatkowo: MGŁA (Fog) na zielono dla klimatu
        *(float*)0xB7C4CC = 0.0f; // Fog R
        *(float*)0xB7C4D0 = 1.0f; // Fog G
        *(float*)0xB7C4D4 = 0.0f; // Fog B
    }
}


void SetGlobalGrovePeds(bool enable) {
    // Adres bazy grup populacji (v1.0): 0x5B2450
    // Jest 32 grupy, każda ma miejsce na modele postaci
    uintptr_t pedGroupBase = 0x5B2450;

    if (enable) {
        for (int i = 0; i < 32; i++) {
            // Każda grupa to zbiór ID modeli (shorty)
            uintptr_t currentGroup = pedGroupBase + (i * 0x1E); // Offset grupy
            
            // Wypełniamy pierwsze 3 sloty modelami Grove Street
            *(unsigned short*)(currentGroup + 0) = 105; // Fam1
            *(unsigned short*)(currentGroup + 2) = 106; // Fam2
            *(unsigned short*)(currentGroup + 4) = 107; // Fam3
            
            // Opcjonalnie: reszta slotów na 105, żeby nikt inny się nie pętał
            for(int s = 3; s < 10; s++) {
                *(unsigned short*)(currentGroup + (s * 2)) = 105;
            }
        }
        PrintStringA("~G~CITIZENS REPLACED BY GROVE", 1000, 1, false);
    }
}

void SetAllTagsCompleted(bool enable) {
    // Adres bazy tagów (v1.0): 0xA9AD68
    // Jest 100 tagów, każdy to 1 bajt (lub flaga bitowa w strukturze)
    uintptr_t tagsBase = 0xA9AD68;

    for (int i = 0; i < 100; i++) {
        if (enable) {
            *(unsigned char*)(tagsBase + i) = 1; // 1 = Zamalowany na zielono
        } else {
            *(unsigned char*)(tagsBase + i) = 0; // 0 = Oryginalny (np. fioletowy Ballas)
        }
    }

    if (enable) {
        // Dodatkowo: Daj nagrodę za wszystkie tagi (Bronie w domu CJ-a)
        // Wywołujemy skryptową flagę ukończenia (opcjonalnie)
        *(int*)0xBAA474 = 100; // Licznik zebranych tagów w statystykach
        PrintStringA("~G~ALL TAGS SPRAYED GREEN", 1000, 1, false);
    }
}


void ProcessGreenVehicleFilter(bool enable) {
    uintptr_t poolAddr = *(uintptr_t*)0xB74494;
    if (!poolAddr) return;

    int maxVehs = *(int*)(poolAddr + 0x8);
    uintptr_t vehsArray = *(uintptr_t*)poolAddr;

    for (int i = 0; i < maxVehs; i++) {
        uintptr_t pVeh = *(uintptr_t*)(vehsArray + (i * 0x4));
        if (!pVeh) continue;

        if (enable) {
            // Pobierz kolory auta (Primary: 0x430, Secondary: 0x431)
            unsigned char color1 = *(unsigned char*)(pVeh + 0x430);
            unsigned char color2 = *(unsigned char*)(pVeh + 0x431);

            // Flaga widoczności (v1.0 offset 0x1A - flagi statusu encji)
            // Ustawiamy bit 0 na 0 (Niewidoczny) lub 1 (Widoczny)
            if (color1 == 86 || color1 == 114 || color2 == 86) {
                *(unsigned char*)(pVeh + 0x1A) |= 0x01; // ZOSTAW WIDOCZNY
            } else {
                *(unsigned char*)(pVeh + 0x1A) &= ~0x01; // UKRYJ
            }
        } else {
            // PRZYWRÓĆ WSZYSTKIE (Gdy cheat wyłączony)
            *(unsigned char*)(pVeh + 0x1A) |= 0x01;
        }
    }
}

void SetGreenBlood(bool enable) {
    // Adresy RGB dla efektu krwi (v1.0)
    // Standardowo: R: 150, G: 0, B: 0 (Ciemnoczerwony)
    unsigned char* bloodR = (unsigned char*)0x8D5100;
    unsigned char* bloodG = (unsigned char*)0x8D5101;
    unsigned char* bloodB = (unsigned char*)0x8D5102;

    if (enable) {
        *bloodR = 0;   // Usuwamy czerwony
        *bloodG = 255; // Maksymalna zieleń
        *bloodB = 0;   // Usuwamy niebieski
    } else {
        // Powrót do oryginału (Czerwony)
        *bloodR = 150;
        *bloodG = 0;
        *bloodB = 0;
    }
}

void SetGreenHUD(bool enable) {
    // Adres bazy kolorów HUD (v1.0): 0xBAB22C
    // Każdy kolor to 4 bajty (RGBA)
    
    unsigned char* healthBar = (unsigned char*)0xBAB22C; // Kolor życia
    unsigned char* armorBar  = (unsigned char*)0xBAB240; // Kolor pancerza
    unsigned char* moneyText = (unsigned char*)0xBAB244; // Kolor pieniędzy

    if (enable) {
        // Życie na Jaskrawy Zielony
        healthBar[0] = 0;   // R
        healthBar[1] = 255; // G
        healthBar[2] = 0;   // B
        
        // Pancerz na Ciemny Zielony (dla kontrastu)
        armorBar[0] = 0;
        armorBar[1] = 150;
        armorBar[2] = 0;

        // Pieniądze na Neonowy Zielony
        moneyText[0] = 50;
        moneyText[1] = 255;
        moneyText[2] = 50;
    } else {
        // Powrót do oryginału (Czerwony/Biały/Zielony)
        healthBar[0] = 180; healthBar[1] = 25; healthBar[2] = 29; // Czerwony
        armorBar[0] = 225;  armorBar[1] = 225; armorBar[2] = 225; // Biały
        moneyText[0] = 54;   moneyText[1] = 104; moneyText[2] = 44;  // Ciemny Zielony
    }
}

void ProcessPoliceOccupants(bool enable) {
    if (!enable) return;

    uintptr_t poolAddr = *(uintptr_t*)0xB74494; // Vehicle Pool
    if (!poolAddr) return;

    int maxVehs = *(int*)(poolAddr + 0x8);
    uintptr_t vehsArray = *(uintptr_t*)poolAddr;

    for (int i = 0; i < maxVehs; i++) {
        uintptr_t pVeh = *(uintptr_t*)(vehsArray + (i * 0x4));
        if (!pVeh) continue;

        // 1. Sprawdź model (596: LA, 597: SF, 598: VG, 523: Bike)
        unsigned short modelID = *(unsigned short*)(pVeh + 0x22); 
        bool isPoliceCar = (modelID >= 596 && modelID <= 598);
        bool isPoliceBike = (modelID == 523);

        if (isPoliceCar || isPoliceBike) {
            // 2. Pobierz kolory (Marker, żeby nie dodawać pasażerów co klatkę)
            unsigned char color1 = *(unsigned char*)(pVeh + 0x430);
            
            if (color1 != 220) { // Jeśli kolor nie jest 220, to znaczy że jeszcze nie "obsłużone"
                *(unsigned char*)(pVeh + 0x430) = 220; // Ustaw kolor na 220 (Marker)

                // 3. Sprawdź czy jest kierowca
                uintptr_t pDriver = *(uintptr_t*)(pVeh + 0x460);
                if (pDriver) {
                    if (isPoliceCar) {
                        // Dodaj pasażerów na wolne miejsca (Siedzenia 0, 1, 2)
                        for (int seat = 0; seat <= 2; seat++) {
                            // Sprawdzanie czy siedzenie wolne (uproszczony offset)
                            uintptr_t pPassenger = *(uintptr_t*)(pVeh + 0x464 + (seat * 4));
                            if (!pPassenger) {
                                // Wywołanie SetupPassenger (pedType 6 = COP)
                                SetupPassenger(pVeh, seat, 6, false, false, false);
                            }
                        }
                    } else if (isPoliceBike) {
                        // Na motocyklu tylko jedno miejsce pasażera (seat 0)
                        uintptr_t pPassenger = *(uintptr_t*)(pVeh + 0x464);
                        if (!pPassenger) {
                            SetupPassenger(pVeh, 0, 6, false, false, false);
                        }
                    }
                }
            }
        }
    }
}

void MakePassengersShoot(uintptr_t pVeh) {
    // Przeszukujemy 3 sloty pasażerów (0, 1, 2)
    for (int seat = 0; seat < 3; seat++) {
        uintptr_t pPassenger = *(uintptr_t*)(pVeh + 0x464 + (seat * 4));
        if (pPassenger) {
            // 1. Daj broń pasażerowi, jeśli jej nie ma (np. MP5 ID 29)
            // Używamy Twojej wcześniejszej logiki z amunicją
            *(int*)(pPassenger + 0x5A0) = 9999; // Amunicja
            
            // 2. Ustaw flagę "Może strzelać z auta" (v1.0 offset 0x46C w CPed)
            *(unsigned char*)(pPassenger + 0x46C) |= 0x20; 

            // 3. Wymuś agresywne AI (PedStat: 0x5A4)
            // Ustawiamy "Tough" lub "Gangster"
            *(int*)(pPassenger + 0x5A4) = 4; 

            // 4. Jeśli w pobliżu jest wróg, wywołaj Drive-By
            // (Wymaga wywołania CTaskComplexDriveByShoot pod 0x641110)
        }
    }
}

if (isPoliceCar) {
    for (int seat = 0; seat <= 2; seat++) {
        uintptr_t pPassenger = *(uintptr_t*)(pVeh + 0x464 + (seat * 4));
        if (!pPassenger) {
            SetupPassenger(pVeh, seat, 24, false, false, false); // 24 = Grove
        } else {
            // Jeśli pasażer już jest, spraw, by był gotowy do walki
            MakePassengersShoot(pVeh);
        }
    }
}

void SetRocketAmmo(bool enable) {
    void* pPlayer = GetPlayerPed();
    if (!pPlayer) return;

    // 1. Pobierz ID aktualnej broni (offset 0x740)
    int weaponID = *(int*)((uintptr_t)pPlayer + 0x740);
    if (weaponID <= 0) return;

    uintptr_t weaponStatsBase = 0xC8AAB8;
    uintptr_t weaponAddress = weaponStatsBase + (weaponID * 0x70); 

    int* pProjectileType = (int*)(weaponAddress + 0x1C); // Offset typu pocisku
    float* pDamage = (float*)(weaponAddress + 0x22);     // Offset obrażeń

    if (enable) {
        // Zmieniamy pocisk na RAKIETĘ (ID 4 lub 5 dla Heat-Seeker)
        *pProjectileType = 4; 
        
        // Zwiększamy obrażenia wybuchu
        *pDamage = 500.0f;

        // Opcjonalnie: Zwiększ zasięg, żeby rakieta nie wybuchła Ci w twarz
        *(float*)(weaponAddress + 0x04) = 1000.0f; 
    } else {
        // Powrót do zwykłych kul (ID 1)
        *pProjectileType = 1;
        *pDamage = 25.0f;
    }
}

void SetHeatSeekingMode(bool enable) {
    void* pPlayer = GetPlayerPed();
    if (!pPlayer) return;

    int weaponID = *(int*)((uintptr_t)pPlayer + 0x740);
    if (weaponID <= 0) return;

    uintptr_t weaponAddress = 0xC8AAB8 + (weaponID * 0x70); 

    int* pProjectileType = (int*)(weaponAddress + 0x1C);
    float* pAccuracy = (float*)(weaponAddress + 0x08);

    if (enable) {
        // TYP 5 = Rakieta naprowadzana (Heat-Seeker)
        *pProjectileType = 5; 
        
        // Zwiększamy celność, żeby rakieta lepiej korygowała lot
        *pAccuracy = 10.0f; 

        // Opcjonalnie: Zwiększamy zasięg widzenia celu (Target Range)
        *(float*)(weaponAddress + 0x00) = 500.0f;
    } else {
        *pProjectileType = 1; // Powrót do kul
    }
}


#define do_toggle(x) \
    if(x) x=false;\
    else x=true;\
    reset_menu();